package com.bjpowernode.mvc.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.bjpowernode.common.constant.AppConstants;
import com.bjpowernode.db.domain.*;
import com.bjpowernode.db.mapper.*;
import com.bjpowernode.db.result.IncomeRecordResult;
import com.bjpowernode.mvc.service.inter.IncomeRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;

@RequiredArgsConstructor
@Service
public class IncomeRecordServiceImpl implements IncomeRecordService {

    private final IncomeRecordMapper incomeRecordMapper;
    private final ProductInfoMapper productInfoMapper;
    private final BidInfoMapper bidInfoMapper;
    private final SysAccountMapper sysAccountMapper;
    private final AccountDetailMapper accountDetailMapper;


    /**
     * 查询最近收益记录
     *
     * @param uid
     * @param offset
     * @param rows
     * @return
     */
    @Override
    public List<IncomeRecordResult> queryIncomeRecordByUid(Integer uid, Integer offset, Integer rows) {

        return incomeRecordMapper.selectIncomeRecord(uid, offset, rows);
    }

    /**
     * 生成收益计划--定时任务  事务控制
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void generateIncomePlan() {

        //1、查询满标的理财产品    产品投资满标时间是昨天的    产品满标状态是1
        QueryWrapper<ProductInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_status", AppConstants.PRODUCT_STA_SELLED);

        //获取当前日期
        Date now = new Date();
        //获取昨天的日期
        DateTime beginTime = DateUtil.truncate(DateUtil.yesterday(), DateField.DAY_OF_MONTH);
        //获取当前日期的日期
        DateTime endTime = DateUtil.truncate(now, DateField.DAY_OF_MONTH);
        //设置查询条件，大于等于(ge)昨天的日期，小于等于(le)当前日期的日期
        queryWrapper.ge("product_full_time", beginTime);
        queryWrapper.le("product_full_time", endTime);

        List<ProductInfo> productInfoList = productInfoMapper.selectList(queryWrapper);

        //2、查询满标产品的投资记录
        //到期时间
        Date expireDate = null;
        //理财产品日利率
        BigDecimal dayRate = null;
        //理财产品利息
        BigDecimal incomeMoney = null;
        //周期
        int cycle = 0;

        for (ProductInfo productInfo : productInfoList) {
            //根据产品类型计算到期时间(满标时间 + 周期)
            if (productInfo.getProductType() == AppConstants.PRODUCT_TYPE_XIN) {
                expireDate = DateUtil.offsetDay(productInfo.getProductFullTime(), productInfo.getCycle());
                cycle = productInfo.getCycle();
            } else {
                expireDate = DateUtil.offsetDay(productInfo.getProductFullTime(), productInfo.getCycle() * 30);
                cycle = productInfo.getCycle() * 30;
            }

            //日利率
            dayRate = productInfo.getRate().divide(new BigDecimal("36000"), 15, RoundingMode.HALF_UP);

            //查询购买理财产品的投资记录
            List<BidInfo> bidInfoList = bidInfoMapper.selectByProductId(productInfo.getId());
            //如果有很多行数据，这种方式对内存消耗很大，可以考虑分页查询多次提交、使用传统的JDBC操作，最后commit事务提交进行优化
            for (BidInfo bidInfo : bidInfoList) {
                //1、计算利息  利息 = 本金 * 日利率 * 周期
                incomeMoney = bidInfo.getBidMoney().multiply(dayRate).multiply(new BigDecimal(cycle));

                //2、增加收益记录
                IncomeRecord incomeRecord = new IncomeRecord();
                //用户ID
                incomeRecord.setUid(bidInfo.getUid());
                //产品ID
                incomeRecord.setProdId(bidInfo.getProdId());
                //投资记录ID
                incomeRecord.setBidId(bidInfo.getId());
                //投资金额
                incomeRecord.setBidMoney(bidInfo.getBidMoney());
                //到期时间
                incomeRecord.setIncomeDate(expireDate);
                //收益金额
                incomeRecord.setIncomeMoney(incomeMoney);
                //收益状态 0 表示未返还  1表示已返还
                incomeRecord.setIncomeStatus(AppConstants.STA_INCOME_PLAN);
                incomeRecordMapper.insert(incomeRecord);

                //3、修改理财产品状态为2
                UpdateWrapper<ProductInfo> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("id", productInfo.getId());
                updateWrapper.set("product_status", AppConstants.PRODUCT_STA_PLAN);
                int update = productInfoMapper.update(null, updateWrapper);

                if (update < 1) {
                    throw new RuntimeException("生成收益计划，更新理财产品状态为2失败！");
                }
            }
        }
    }

    /**
     * 生成收益返还
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void generateIncomeBack() {
        //1、查找符合条件的收益记录
        QueryWrapper<IncomeRecord> queryWrapper = new QueryWrapper<>();
        DateTime yesterday = DateUtil.yesterday();
        queryWrapper.eq("income_date", DateUtil.truncate(yesterday, DateField.DAY_OF_MONTH));
        queryWrapper.eq("income_status", AppConstants.STA_INCOME_PLAN);
        List<IncomeRecord> incomeRecordList = incomeRecordMapper.selectList(queryWrapper);
        //每条收益记录返回收益和本金
        int update = 0;
        for (IncomeRecord incomeRecord : incomeRecordList) {
            //2、更新用户可用资金
            update = sysAccountMapper.updateAvailableMoneyByIncomeBack(incomeRecord.getUid(), incomeRecord.getIncomeMoney(), incomeRecord.getBidMoney());
            if (update < 1) {
                throw new RuntimeException("收益返还，更新资金账号失败！");
            }

            //3、更新账号流水
            //3.1更新账号收益返还本金流水
            AccountDetail accountDetail = new AccountDetail();
            //操作时间
            accountDetail.setActionTime(new Date());
            //用户ID
            accountDetail.setUid(incomeRecord.getUid());
            //账号备注
            accountDetail.setMemo("收益返还本金：" + incomeRecord.getBidMoney());
            //账号操作金额
            accountDetail.setMoney(incomeRecord.getIncomeMoney());
            //对账号的操作
            accountDetail.setAction(AppConstants.OPERATION_ADD);

            int insert = accountDetailMapper.insert(accountDetail);

            if (insert < 1) {
                throw new RuntimeException("收益返还本金，更新账号流水失败！");
            }

            //3.2更新账号收益返还收益流水
            accountDetail = new AccountDetail();
            //操作时间
            accountDetail.setActionTime(new Date());
            //用户ID
            accountDetail.setUid(incomeRecord.getUid());
            //账号备注
            accountDetail.setMemo("收益返还收益：" + incomeRecord.getIncomeMoney());
            //账号操作金额
            accountDetail.setMoney(incomeRecord.getIncomeMoney());
            //对账号的操作
            accountDetail.setAction(AppConstants.OPERATION_ADD);

            insert = accountDetailMapper.insert(accountDetail);

            if (insert < 1) {
                throw new RuntimeException("收益返还利息，更新账号流水失败！");
            }

            //更新此收益记录的状态为1状态
            update = incomeRecordMapper.updateStatus(incomeRecord.getId(), AppConstants.STA_INCOME_BACK);
            if (update < 1) {
                throw new RuntimeException("收益返还，更新收益记录状态失败！");
            }
        }

    }
}
